#pragma once
#include <string>
#include <vector>

#if defined(WIN32) && defined(USE_Transcoding)
#include <Windows.h>
#endif //  defined(WIN32)


namespace sh
{

std::vector<std::string> split(std::string const& str, const std::string& separator);
std::string toHex(const uint8_t* p, size_t len);
std::string toHex(const char* p, size_t len);

#ifdef WIN32
std::string gbkToUtf8(const std::string& gbkStr);
std::string utf8ToGbk(const std::string& gbkStr);
#endif

/*
* //////////////////////////////////////////////////////////////////////////////////////////
*
*
*
* //////////////////////////////////////////////////////////////////////////////////////////
*/



inline std::vector<std::string> split(std::string const& str, const std::string& separator) {
    std::vector<std::string> list;
    size_t l{ 0 }, r{ 0 };
    while (r < str.size()) {
        r = str.find(separator, l);
        if (r == std::string::npos) r = str.size();
        std::string chunk;
        if(r != l) chunk = std::string(str.begin() + l, str.begin() + r);
        list.emplace_back(chunk);
        l = r + separator.size();
    }
    return list;
}

inline std::string toHex(const uint8_t* p, size_t len) {
    static const char* hexStr = "0123456789ABCDEF";
    if (!p || !len) return {};
    std::string s(len * 2, 0);
    for (size_t i = 0; i < len; i++) {
        s[2 * i] = hexStr[p[i] / 16];
        s[2 * i + 1] = hexStr[p[i] % 16];
    }
    return s;
}
inline std::string toHex(const char* p, size_t len) { return toHex((const uint8_t*)p, len); }




#if defined(WIN32) && defined(USE_Transcoding)
inline std::string gbkToUtf8(const std::string& gbkStr) {
    // Step 1: Convert GBK to Wide Char (UTF-16)
    int wideSize = MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, NULL, 0);

    if (wideSize == 0) return ""; // failed

    std::wstring wideStr(wideSize, 0);
    MultiByteToWideChar(CP_ACP, 0, gbkStr.c_str(), -1, &wideStr[0], wideSize);

    // Step 2: Convert Wide Char (UTF-16) to GBK
    int utf8Size = WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, NULL, 0, NULL, NULL);

    if (utf8Size == 0) return "";

    std::string utf8Str(utf8Size, 0);
    WideCharToMultiByte(CP_UTF8, 0, wideStr.c_str(), -1, &utf8Str[0], utf8Size, NULL, NULL);
    utf8Str.pop_back(); // Remove the null terminator added by the conversion functions
    return utf8Str;
}

inline std::string utf8ToGbk(std::string const& utf8Str) {
    // Step 1: Convert UTF-8 to Wide Char (UTF-16)
    int wideCharLen = MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, nullptr, 0);
    if (wideCharLen == 0) throw std::runtime_error("Failed to convert from UTF-8 to wide char.");

    std::wstring wideStr(wideCharLen, 0);
    MultiByteToWideChar(CP_UTF8, 0, utf8Str.c_str(), -1, &wideStr[0], wideCharLen);

    // Step 2: Convert Wide Char (UTF-16) to GBK
    int gbkLen = WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, nullptr, 0, nullptr, nullptr);
    if (gbkLen == 0) throw std::runtime_error("Failed to convert from wide char to GBK.");

    std::string gbkStr(gbkLen, 0);
    WideCharToMultiByte(CP_ACP, 0, wideStr.c_str(), -1, &gbkStr[0], gbkLen, nullptr, nullptr);

    gbkStr.pop_back(); // Remove the null terminator added by the conversion functions
    return gbkStr;
}
#endif // WIN32

} // namespace sh
